//实现一个promise
/**
 * 构造函数：初始化Promise的状态和值，以及存储回调函数的数组。
 * 
 * then方法：根据Promise的状态，执行对应的回调函数。
 * 如果状态为fulfilled，执行onFulfilled回调函数；
 * 如果状态为rejected，执行onRejected回调函数；
 * 如果状态为pending，将回调函数存储到对应的数组中。
 * 同时，返回一个新的Promise对象，用于链式调用。
 * 
 * resolvePromise方法：用于处理then方法中回调函数返回值的情况。
 * 如果返回值是一个Promise对象，需要递归调用resolvePromise方法，直到返回值不是Promise对象为止。
 * 如果返回值是一个普通值，直接调用resolve方法。
 * 
 * catch方法：用于捕获Promise的rejected状态，返回一个新的Promise对象。
 * 
 * resolve方法：返回一个fulfilled状态的Promise对象。
 * 
 * reject方法：返回一个rejected状态的Promise对象。
 * 
 * all方法：接收一个Promise对象数组，返回一个新的Promise对象。
 * 当所有Promise对象都变为fulfilled状态时，返回一个包含所有Promise对象返回值的数组；
 * 如果有一个Promise对象变为rejected状态，直接返回rejected状态的Promise对象。
*/
class MyPromise {
  constructor(executor) {
    this.status = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.status === 'pending') {
        this.status = 'fulfilled';
        this.value = value;
        this.onResolvedCallbacks.forEach((fn) => fn());
      }
    };

    const reject = (reason) => {
      if (this.status === 'pending') {
        this.status = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
    onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason };

    const promise2 = new MyPromise((resolve, reject) => {
      if (this.status === 'fulfilled') {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.status === 'rejected') {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else {
        this.onResolvedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });

    return promise2;
  }

  resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {
      return reject(new TypeError('Chaining cycle detected for promise'));
    }

    let called = false;

    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
      try {
        const then = x.then;

        if (typeof then === 'function') {
          then.call(
            x,
            (y) => {
              if (called) return;
              called = true;
              this.resolvePromise(promise2, y, resolve, reject);
            },
            (r) => {
              if (called) return;
              called = true;
              reject(r);
            }
          );
        } else {
          resolve(x);
        }
      } catch (error) {
        if (called) return;
        called = true;
        reject(error);
      }
    } else {
      resolve(x);
    }
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }

  static resolve(value) {
    return new MyPromise((resolve) => {
      resolve(value);
    });
  }

  static reject(reason) {
    return new MyPromise((_, reject) => {
      reject(reason);
    });
  }

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const result = [];
      let count = 0;

      const processResultByKey = (value, index) => {
        result[index] = value;
        if (++count === promises.length) {
          resolve(result);
        }
      };

      for (let i = 0; i < promises.length; i++) {
        const promise = promises[i];
        if (promise && typeof promise.then === 'function') {
          promise.then(
            (value) => processResultByKey(value, i),
            (reason) => reject(reason)
          );
        } else {
          processResultByKey(promise, i);
        }
      }
    });
  }

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        const promise = promises[i];
        if (promise && typeof promise.then === 'function') {
          promise.then(
            (value) => resolve(value),
            (reason) => reject(reason)
          );
        } else {
          resolve(promise);
        }
      }
    });
  }
}
// Example usage of MyPromise:

const promise1 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('Promise 1 resolved');
  }, 1000);
});

const promise2 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('Promise 2 resolved');
  }, 2000);
});

const promise3 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject('Promise 3 rejected');
  }, 1500);
});

MyPromise.all([promise1, promise2])
  .then((result) => {
    console.log(result); // ['Promise 1 resolved', 'Promise 2 resolved']
  })
  .catch((error) => {
    console.log(error);
  });

MyPromise.race([promise1, promise2])
  .then((result) => {
    console.log(result); // 'Promise 1 resolved'
  })
  .catch((error) => {
    console.log(error);
  });

MyPromise.all([promise1, promise2, promise3])
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.log(error); // 'Promise 3 rejected'
  });